import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List strs = [
    "刘亦菲[呲牙][呲牙][呲牙]",
    "刘亦菲[呲牙][不是表情][委屈]",
    "[爱心]https://www.baidu.com/[呲牙]小四"
  ];
  final List emojis = ["呲牙", "委屈", "爱心"];
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text("图文混排"),
        ),
        body: ListView.builder(
            padding: const EdgeInsets.all(10),
            itemCount: strs.length,
            itemBuilder: (ctx, index) {
              return Container(
                padding: const EdgeInsets.all(10),
                height: 100,
                color: index % 2 == 0 ? Colors.yellow : Colors.grey,
                child: getRichText(strs[index]),
              );
            }),
      ),
    );
  }

  getRichText(String text) {
    List<InlineSpan> textSapns = [];
    String urlExpString =
        r"(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?";
    String emojExpString = r"\[.{1,4}?\]";
    RegExp exp = RegExp('$urlExpString|$emojExpString');

    //正则表达式是否在字符串[input]中有匹配。
    if (exp.hasMatch(text)) {
      Iterable<RegExpMatch> matches = exp.allMatches(text);

      int index = 0;
      int count = 0;
      for (var matche in matches) {
        count++;
        String c = text.substring(matche.start, matche.end);
        //表情在首位
        if (index == matche.start) {
          index = matche.end;
        }
        //表情不在首位
        else if (index < matche.start) {
          String leftStr = text.substring(index, matche.start);
          index = matche.end;
          textSapns.add(TextSpan(
              text: leftStr,
              style: const TextStyle(color: Colors.black, fontSize: 17)));
        }

        //匹配到的网址
        if (RegExp(urlExpString).hasMatch(c)) {
          textSapns.add(TextSpan(
              text: c,
              style: const TextStyle(color: Colors.red, fontSize: 17),
              recognizer: TapGestureRecognizer()
                ..onTap = () async {
                  await launch(c);
                  //打开浏览器
                  print(c);
                }));
        }
        //匹配到的表情
        else if (RegExp(emojExpString).hasMatch(c)) {
          //[:偷笑] 去掉[:] = 偷笑
          String emojiStr = c.substring(1, c.length - 1);
          textSapns.add(WidgetSpan(
              style: const TextStyle(height: 1.5),
              //判断表情是否存在
              child: emojis.contains(emojiStr)
                  ? Image.asset(
                      "lib/images/$emojiStr.png",
                      width: 22,
                      height: 22,
                    )
                  : Text(c,
                      style:
                          const TextStyle(color: Colors.black, fontSize: 17))));
        }

        //是否是最后一个表情,并且后面是否有字符串
        if (matches.length == count && text.length > index) {
          String rightStr = text.substring(index, text.length);
          textSapns.add(TextSpan(
              text: rightStr,
              style: const TextStyle(color: Colors.black, fontSize: 17)));
        }
      }
    } else {
      textSapns.add(TextSpan(
          text: text,
          style: const TextStyle(color: Colors.black, fontSize: 17)));
    }

    return Text.rich(TextSpan(children: textSapns));
  }
}
